/**
 * Project Name : cloudlead-common-api
 * File Name : ExceptionConvertResponse.java
 * Package Name : com.cloudlead.common.worker.utils
 * Date : 2014年7月18日下午6:13:58
 * Copyright (c) 2014, cloudlead.com.cn All Rights Reserved.
 */
package com.cloudlead.common.lang.utils;

import com.cloudlead.common.lang.BizRuntimeException;
import com.cloudlead.common.lang.api.ErrorMeta;
import com.cloudlead.common.lang.api.ErrorActionResponse;
import com.cloudlead.common.lang.api.ResponseCode;
import com.cloudlead.common.lang.exception.*;

/**
 * @author 陆林(lulin@cloudlead-partners.com)
 * @version 2.0
 * @date 2014年7月18日 下午6:13:58
 * @since 2.0
 */
public class ExceptionHelper {

    public static ErrorActionResponse toResponse(Throwable ex) {
        ErrorMeta errorLog = toActionError(ex);

        ErrorActionResponse response = new ErrorActionResponse(errorLog);
        if (ex instanceof BizRuntimeException) {
            BizRuntimeException e = (BizRuntimeException) ex;
            response.setCode(e.getBaseCode() == null ? ResponseCode.INTERNAL_SERVER_ERROR
                    .code() : e.getCode());
            response.setMessage(errorLog.getMessage());
        } else {
            response.setCode(ResponseCode.INTERNAL_SERVER_ERROR.code());
            response.setMessage(errorLog.getMessage());
        }
        return response;
    }

    public static ErrorMeta toActionError(Throwable ex) {
        ErrorMeta errorLog = new ErrorMeta();
        errorLog.setMessage(ex.getMessage());
        errorLog.setErrorClass(ex.getClass().getName());
        Throwable rootCause = rootCause(ex);
        StackTraceElement[] stackTrace = rootCause.getStackTrace();
        errorLog.setCauseMessage(rootCause.getMessage());
        errorLog.setCauseException(rootCause.getClass().getName());
        if (null != stackTrace && stackTrace.length > 0) {
            StackTraceElement stackTraceElement = stackTrace[0];
            errorLog.setCauseClass(stackTraceElement.getClassName());
            errorLog.setCauseClassMethod(stackTraceElement.getMethodName());
            errorLog.setCauseClassLine(stackTraceElement.getLineNumber());
        }
        return errorLog;
    }

    public static Exception toException(int errorCode, String message) {
        int code = (errorCode / 100) * 100;
        int bizCode = errorCode % 100;
        if (ResponseCode.BAD_REQUEST.code() == code) {
            return new BadRequestException(bizCode, message);
        } else if (ResponseCode.DATA_ACCESS_ERROR.code() == code) {
            return new DataAccessException(bizCode, message);
        } else if (ResponseCode.FORBIDDEN.code() == code) {
            return new ForbiddenException(bizCode, message);
        } else if (ResponseCode.NOT_SUPPORTED_ERROR.code() == code) {
            return new NotSupportedException(bizCode, message);
        } else if (ResponseCode.RESOURCE_NOT_ACCEPTABLE.code() == code) {
            return new RequestNotAcceptableException(bizCode, message);
        } else if (ResponseCode.RESOURCE_NOT_FOUND.code() == code) {
            return new ResourceNotFoundException(bizCode, message);
        } else if (ResponseCode.INTERNAL_SERVER_ERROR.code() == code) {
            return new ServerErrorException(bizCode, message);
        } else if (ResponseCode.SERVICE_UNAVAILABLE.code() == code) {
            return new ServiceUnavailableException(bizCode, message);
        } else if (ResponseCode.REQUEST_TIMEOUT.code() == code) {
            return new TimeoutException(bizCode, message);
        } else if (ResponseCode.SC_UNAUTHORIZED.code() == code) {
            return new UnauthorizedException(bizCode, message);
        }
        return new ServerErrorException(message);
    }

    static Throwable rootCause(Throwable wrapped) {
        Throwable unwrapped = wrapped;
        while (true) {
            if (null != unwrapped.getCause()) {
                return rootCause(unwrapped.getCause());
            } else {
                return unwrapped;
            }
        }
    }

}
